package physicalObjects;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import simulation.Simulation;
import forces.Force;


/**
 *
 * @author Robert C. Duvall, modified by Qiang and Michael
 */
public class Spring implements PhysicalObj {
    /**
     * Unless the length change of the spring is greater than this threshold,
     * we take the spring as in relax mode.
     */
    private static final double RELAXTHRESHOLD = 0.001;

    /**
     * The masses connecting to the two ends of the spring.
     */
    private Mass myStart;
    private Mass myEnd;
    /**
     * The rest length of the spring.
     */
    private double myLength;
    /**
     * The spring constant.
     */
    private double myK;
    /**
     * The ID of the spring
     */
    private int myID;


    /**
     * Constructor for this class.
     * @param start Mass on start end of the muscle
     * @param end Mass on end of muscle
     * @param length Rest length of the bar
     * @param kVal k value associated with the spring/bar
     */
    public Spring(Mass start, Mass end, double length, double kVal) {
        myStart = start;
        myEnd = end;
        myLength = length;
        myK = kVal;
    }

    /**
     *
     * @param pen Graphics2D object to paint the spring
     */
    public void paint(Graphics2D pen) {
        /**
         * Locate the two ends of the spring and calculate its length
         */
        int xStart = (int) myStart.getCenter().getX();
        int yStart = (int) myStart.getCenter().getY();
        int xEnd = (int) myEnd.getCenter().getX();
        int yEnd = (int) myEnd.getCenter().getY();
        double dx = xStart - xEnd;
        double dy = yStart - yEnd;
        double len = Math.sqrt(dx * dx + dy * dy) - myLength;

        /**
         * Draw the spring with white color if it is in relax. With
         * blue color if it is shrinking and with red color if it is expanding
         */
        if (Math.abs(len) < RELAXTHRESHOLD) {
            pen.setColor(Color.WHITE);
        }
        else if (len < 0.0) {
            pen.setColor(Color.BLUE);
        }
        else {
            pen.setColor(Color.RED);
        }
        pen.drawLine(xStart, yStart, xEnd, yEnd);
    }

    /**
     * @param canvas The simulation where this is running
     * @param dt Time changes
     */
    public void update(Simulation canvas, double dt) {
        /**
         * Locate the masses and calculate the distance between them.
         */
        Point2D start = myStart.getCenter();
        Point2D end = myEnd.getCenter();
        double dx = start.getX() - end.getX();
        double dy = start.getY() - end.getY();

        /**
         * Calculate the elastic force within the spring and apply
         * that to both masses.
         */
        Force f = new Force(Force.angleBetween(dx, dy), myK
                * (myLength - Force.distanceBetween(dx, dy)));
        myStart.applyForce(f);
        f.negate();
        myEnd.applyForce(f);
    }

    /**
     *
     * @param newLength The value myLength is to be set to
     */
    public void setMyLength(double newLength) {
        myLength = newLength;
    }

    /**
     *
     * @return The myLength variable of the spring
     */
    public double getMyLength() {
        return myLength;
    }

    /**
     *
     * @return returns the Mass at the start-end.
     */
    public Mass getMyStart() {
        return myStart;
    }

    /**
     *
     * @return returns the mass at the other end.
     */
    public Mass getMyEnd() {
        return myEnd;
    }
    
    /**
     * Tests to see if this spring matches the given id.
     * @param id The ID number you are testing
     * @return Returns true if the ID number matches, false otherwise
     */
    public boolean match (int id) {
        return myID == id;
    }
}
